#ifndef _I_BASE_MATERIAL_H_
#define _I_BASE_MATERIAL_H_

#pragma warning(disable:4996)

#include "I_Buffer.h"

#include "T_Buffer_CU.h"
#include "T_Buffer_GL.h"

#include "../cuCommon/cuTypes.h"

#include "../rtCommon/xobj_string.h"

#include "../FastXML/FastXml.h"

class I_BaseMaterial : public NVSHARE::FastXmlInterface
{
public:
	I_BaseMaterial(){}
	virtual ~I_BaseMaterial(){}

	virtual bool processElement(const char *elementName, NxI32 argc, const char **argv, const char *elementData, NxI32 lineno) = 0;
};

template <class T4, class T>
class T_BaseMaterial : public I_BaseMaterial
{
public:
	T_BaseMaterial(){}
	virtual ~T_BaseMaterial(){}

	virtual T4		ambient() = 0;
	virtual void	ambient(const T4 &a) = 0;

	virtual T4		diffuse() = 0;
	virtual void	diffuse(const T4 &d) = 0;

	virtual T4		specular() = 0;
	virtual void	specular(const T4 &s) = 0;

	virtual T4		emission() = 0;
	virtual void	emission(const T4 &e) = 0;

	virtual T			shininess()=0;
	virtual void	shininess(T sh) = 0;

	virtual bool processElement(const char *elementName, NxI32 argc, const char **argv, const char *elementData, NxI32 lineno)
	{
		if (strcmp(elementName, "Material") == 0)
		{
			if ((argc != 2) || strcmp(argv[0], "type") != 0 || strcmp(argv[1], "BaseMaterial") != 0 )
				return false;
		}

		if (strcmp(elementName, STRING_V_AMBIENT) == 0)
		{
			float x, y, z, w;
			sscanf(elementData, "%f%f%f%f", &x, &y, &z, &w);
			T4 a = {x, y, z, w};
			ambient(a);			
		}

		if (strcmp(elementName, STRING_V_DIFFUSE) == 0)
		{
			float x, y, z, w;
			sscanf(elementData, "%f%f%f%f", &x, &y, &z, &w);
			T4 d = {x, y, z, w};
			diffuse(d);
		}

		if (strcmp(elementName, STRING_V_SPECULAR) == 0)
		{
			float x, y, z, w;
			sscanf(elementData, "%f%f%f%f", &x, &y, &z, &w);
			T4 s = {x, y, z, w};
			specular(s);
		}

		if (strcmp(elementName, STRING_V_EMISSION) == 0)
		{
			float x, y, z, w;
			sscanf(elementData, "%f%f%f%f", &x, &y, &z, &w);
			T4 e = {x, y, z, w};
			emission(e);
		}

		if (strcmp(elementName, STRING_V_SHININESS) == 0)
		{
			float s;
			sscanf(elementData, "%f", &s);
			T sh = s;
			shininess(sh);
		}

		return true;
	}

	virtual bool Serialize(const char * fileName)
	{
		T4 v;
		T  s;
		FILE * f = fopen(fileName, "w");
		if (f == NULL) return false;

		fprintf(f, "<?xml version=%s?>\n", "\"1\"");

		fprintf(f, "\t<Material type=\"%s\">\n", "BaseMaterial");
		fprintf(f, "\t\t<BaseMaterial>\n");

		v = ambient();
		fprintf(f, "\t\t\t<%s>\n", STRING_V_AMBIENT);
		fprintf(f, "\t\t\t\t%f %f %f %f\n",  v.x, v.y, v.z, v.w);
		fprintf(f, "\t\t\t<\\%s>\n", STRING_V_AMBIENT);

		v = diffuse();
		fprintf(f, "\t\t\t<%s>\n", STRING_V_DIFFUSE);
		fprintf(f, "\t\t\t\t%f %f %f %f\n",  v.x, v.y, v.z, v.w);
		fprintf(f, "\t\t\t<\\%s>\n", STRING_V_DIFFUSE);

		v = specular();
		fprintf(f, "\t\t\t<%s>\n", STRING_V_SPECULAR);
		fprintf(f, "\t\t\t\t%f %f %f %f\n",  v.x, v.y, v.z, v.w);
		fprintf(f, "\t\t\t<\\%s>\n", STRING_V_SPECULAR);

		v = emission();
		fprintf(f, "\t\t\t<%s>\n", STRING_V_EMISSION);
		fprintf(f, "\t\t\t\t%f %f %f %f\n",  v.x, v.y, v.z, v.w);
		fprintf(f, "\t\t\t<\\%s>\n", STRING_V_EMISSION);

		s = shininess();
		fprintf(f, "\t\t\t<%s>\n", STRING_V_SHININESS);
		fprintf(f, "\t\t\t\t%f\n", s);
		fprintf(f, "\t\t\t<\\%s>\n", STRING_V_SHININESS);

		fprintf(f, "\t\t<\\BaseMaterial>\n");
		fprintf(f, "\t<\\Material>\n");

		fclose(f);

		return true;
	}

	virtual bool Deserialize(const char * fileName)
	{
		NVSHARE::FastXml *pXml = NVSHARE::createFastXml();

		bool result = pXml->processXmlFile(fileName, this);

		NVSHARE::releaseFastXml(pXml);

		return result;
	}
};

template <class T4, class T>
class T_cu_BaseMaterial : public T_BaseMaterial<T4, T>, public T_Buffer_CU<T4>
{
public:
	T_cu_BaseMaterial(){}
	virtual ~T_cu_BaseMaterial(){}

	virtual T4		ambient()
	{
		return ((T4*)m_hptr)[0];
	}
	virtual void	ambient(const T4 & a)
	{
		((T4*)m_hptr)[0] = a;
	}

	virtual T4		diffuse()
	{
		return ((T4*)m_hptr)[1];
	}
	virtual void	diffuse(const T4 &d)
	{
		((T4*)m_hptr)[1] = d;
	}

	virtual T4		specular()
	{
		return ((T4*)m_hptr)[2];
	}
	virtual void	specular(const T4 &d)
	{
		((T4*)m_hptr)[2] = d;
	}

	virtual T4		emission()
	{
		return ((T4*)m_hptr)[3];
	}
	virtual void	emission(const T4 & a)
	{
		((T4*)m_hptr)[3] = a;
	}

	virtual T			shininess()
	{
		return ((T4*)m_hptr)[3].w;
	}

	virtual void	shininess(T sh)
	{
		((T4*)m_hptr)[3].w = sh;
	}
};


template <class T4, class T>
class T_gl_BaseMaterial : public T_BaseMaterial<T4, T>, public T_Buffer_GL<T4>
{
public:
	T_gl_BaseMaterial(){}
	virtual ~T_gl_BaseMaterial(){}

	virtual T4		ambient()
	{
		return ((T4*)m_hptr)[0];
	}
	virtual void	ambient(const T4 & a)
	{
		((T4*)m_hptr)[0] = a;
	}

	virtual T4		diffuse()
	{
		return ((T4*)m_hptr)[1];
	}
	virtual void	diffuse(const T4 &d)
	{
		((T4*)m_hptr)[1] = d;
	}

	virtual T4		specular()
	{
		return ((T4*)m_hptr)[2];
	}
	virtual void	specular(const T4 &s)
	{
		((T4*)m_hptr)[2] = s;
	}

	virtual T4		emission()
	{
		return ((T4*)m_hptr)[3];
	}
	virtual void	emission(const T4 & e)
	{
		((T4*)m_hptr)[3] = e;
	}

	virtual T			shininess()
	{
		return ((T4*)m_hptr)[3].w;
	}

	virtual void	shininess(T sh)
	{
		((T4*)m_hptr)[3].w = sh;
	}
};

#endif